package com.thor.palmmall.impl.pay;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.thor.commons.exception.ThorServiceException;
import com.thor.commons.util.Assert;
import com.thor.palmmall.api.elecharges.EleChargesBill;
import com.thor.palmmall.api.elecharges.EleChargesBillState;
import com.thor.palmmall.api.pay.union.UnionPayService;
import com.thor.palmmall.dao.elecharges.EleChargesBillDao;
import com.thor.palmmall.dao.elecharges.PEleChargesBill;
import com.thor.palmmall.dao.elecharges.converter.EleChargesBillConverter;
import com.thor.palmmall.util.pay.UnionPayUtil;
import com.thor.palmmall.util.pay.tool;
import com.unionpay.acp.sdk.AcpService;
import com.unionpay.acp.sdk.SDKConfig;

public class UnionPayServiceImpl implements UnionPayService {

  private final String NOTIFY_FLAG_SUCCESS = "success";
  private final String NOTIFY_FLAG_FAILED = "failed";

  private static final Logger logger = LoggerFactory.getLogger(UnionPayServiceImpl.class);

  @Autowired
  private EleChargesBillDao eleChargesBillDao;

  @Autowired
  private UnionPayConfig unionPayConfig;

  @Override
  public String getUnionPayTradeNo(Map<String, String> params) throws ThorServiceException {
    Assert.assertArgumentNotNull(params, "params");
    //加载unionSDK的配置信息
    UnionPayUtil.initUnionPayConfig(unionPayConfig);
    
    Map<String, String> contentData = new HashMap<String, String>();
    // 创建银联消费接口参数
    createUnionPayConsumeParam(params, contentData);

    /** 对请求参数进行签名并发送http post请求，接收同步应答报文 **/
    Map<String, String> reqData = AcpService.sign(contentData, "UTF-8");
    // 报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
    String requestAppUrl = SDKConfig.getConfig().getAppRequestUrl();
    // 交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
    Map<String, String> rspData = AcpService.post(reqData, requestAppUrl, "UTF-8");
    // 发送请求报文并接受同步应答（默认连接超时时间30秒，读取返回结果超时时间30秒）;这里调用signData之后，调用submitUrl之前不能对submitFromData中的键值对做任何修改，如果修改会导致验签不通过

    if (rspData.isEmpty()) {
      logger.error("-----------未获取到返回报文或返回http状态码非200----------------");
      throw new ThorServiceException("未获取到返回报文或返回http状态码非200");
    }

    if (!AcpService.validate(rspData, "UTF-8")) {
      logger.debug("------------------------验证签名成功---------------------------");
      throw new ThorServiceException("验证签名失败");
    }

    String respCode = rspData.get("respCode");
    if (!("00").equals(respCode)) {
      logger
          .debug("------------------------银联受理订单号获取成功,错误代码---------------------------" + respCode);
      throw new ThorServiceException("银联交易号获取失败,错误代码:" + respCode);
    }
    logger.debug(
        "------------------------银联受理订单号获取成功---------------------------" + rspData.get("tn"));
    return rspData.get("tn");
  }

  private void createUnionPayConsumeParam(Map<String, String> params,
      Map<String, String> contentData) {

    Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
    while (iterator.hasNext()) {
      Map.Entry<String, String> entry = iterator.next();
      contentData.put(entry.getKey(), entry.getValue());
    }

    contentData.put("merId", unionPayConfig.getMerId());

    /*** 银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改 ***/
    contentData.put("version", SDKConfig.getConfig().getVersion()); // 版本号
                                                                    // 全渠道默认值

    contentData.put("encoding", "UTF-8"); // 字符集编码 可以使用UTF-8,GBK两种方式
    contentData.put("signMethod", SDKConfig.getConfig().getSignMethod()); // 签名方法
    contentData.put("txnType", "01"); // 交易类型 01:消费
    contentData.put("txnSubType", "01"); // 交易子类 01：消费
    contentData.put("bizType", "000201"); // 填写000201
    contentData.put("channelType", "08"); // 渠道类型 08手机

    /*** 商户接入参数 ***/
    contentData.put("accessType", "0"); // 接入类型，商户接入填0 ，不需修改（0：直连商户， 1： 收单机构
                                        // 2：平台商户）
    contentData.put("accType", "01"); // 账号类型 01：银行卡02：存折03：IC卡帐号类型(卡介质)
    contentData.put("currencyCode", "156"); // 境内商户固定 156 人民币
    contentData.put("backUrl", SDKConfig.getConfig().getBackUrl());

  }

  @Override
  public boolean callBack(String request) {
    logger.debug("--------接收后台通知开始---------");

    // 获取银联通知服务器发送的后台通知参数
    Map<String, String> reqParam = getAllRequestParam(request);
    logger.debug(reqParam.toString());

    Map<String, String> valideData = null;
    if (null != reqParam && !reqParam.isEmpty()) {
      Iterator<Entry<String, String>> it = reqParam.entrySet().iterator();
      valideData = new HashMap<String, String>(reqParam.size());
      while (it.hasNext()) {
        Entry<String, String> e = it.next();
        String key = (String) e.getKey();
        String value = (String) e.getValue();
        valideData.put(key, value);
      }
    }
    EleChargesBill bill = eleChargesBillDao.getByBillNumber(valideData.get("orderId"));// 获取后台通知的数据，其他字段也可用类似方式获取
    if (bill == null) {
      return false;
    }
    if (bill.getState().equals(EleChargesBillState.FINISH)) {
      return true;
    }

    if (!AcpService.validate(valideData, "UTF-8")) {
      bill.setNotifyFlag(NOTIFY_FLAG_FAILED);
      PEleChargesBill billTOSave = EleChargesBillConverter.getInstance().convert(bill);
      eleChargesBillDao.saveEleChargesBill(billTOSave, tool.getOperateInfo());
      return false;
    }
    logger.debug("----------------验证签名结果[成功].-----------------");

    try {
      SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmss");
      bill.setActionTime(fmt.parse(valideData.get("txnTime")));
    } catch (Exception e) {
      e.printStackTrace();
    }
    bill.setState(EleChargesBillState.PAID);
    bill.setNotifyFlag(NOTIFY_FLAG_SUCCESS); // 回调使用单独的标志字段
    bill.setTransactioNo(valideData.get("queryId"));
    bill.setPayCardNo(valideData.get("payCardNo"));
    PEleChargesBill billTOSave = EleChargesBillConverter.getInstance().convert(bill);
    eleChargesBillDao.saveEleChargesBill(billTOSave, tool.getOperateInfo());
    return true;
  }

  /**
   * 获取请求参数中所有的信息
   * 
   * @param request
   * @return
   */
  public static Map<String, String> getAllRequestParam(final String request) {
    Map<String, String> res = new HashMap<String, String>();
    String[] keyValueArr = request.split("&");
    for (String value : keyValueArr) {
      String[] keyValue = value.split("=");
      if (keyValue.length >= 2) {
        try {
          res.put(keyValue[0], URLDecoder.decode(keyValue[1], "utf-8"));
        } catch (UnsupportedEncodingException e) {
          e.printStackTrace();
        }
      }
    }
    return res;
  }
}
